package cn.iocoder.yudao.module.resource.service.roletextaudio;

import cn.hutool.core.io.file.FileNameUtil;
import cn.iocoder.yudao.module.infra.service.file.FileService;
import cn.iocoder.yudao.module.infra.service.file.UploadFileResult;
import cn.iocoder.yudao.module.infra.tts.TTSServiceFactory;
import cn.iocoder.yudao.module.resource.common.LmrobotResourceConfig;
import cn.iocoder.yudao.module.resource.controller.admin.audio.vo.AudioRelationSaveVo;
import cn.iocoder.yudao.module.resource.controller.admin.audio.vo.LmAudioSaveReqVO;
import cn.iocoder.yudao.module.resource.controller.admin.audiotext.vo.AudioTextRelation;
import cn.iocoder.yudao.module.resource.dal.dataobject.audio.LmAudioDO;
import cn.iocoder.yudao.module.resource.dal.dataobject.audiotext.AudioTextDO;
import cn.iocoder.yudao.module.resource.dal.dataobject.audiotone.AudioToneDO;
import cn.iocoder.yudao.module.resource.dal.dataobject.roletextaudio.RoleTextAudioDO;
import cn.iocoder.yudao.module.resource.dal.mysql.audio.LmAudioMapper;
import cn.iocoder.yudao.module.resource.dal.mysql.audiotext.AudioTextMapper;
import cn.iocoder.yudao.module.resource.dal.mysql.roletextaudio.RoleTextAudioMapper;
import cn.iocoder.yudao.module.resource.service.audio.LmAudioService;
import cn.iocoder.yudao.module.resource.service.audiotone.AudioToneService;
import com.alibaba.fastjson.JSON;
import io.netty.util.concurrent.DefaultEventExecutor;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.EventExecutorGroup;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 文本转角色音频
 *
 * @author 王广帅
 * @version 1.0.0
 * @since 2024/12/18 23:23
 */
@Service
@Slf4j
public class TextConvertRoleAudioService {

    @Resource
    private RoleTextAudioMapper roleTextAudioMapper;
    @Resource
    private LmAudioMapper lmAudioMapper;
    @Resource
    private AudioToneService audioToneService;
    @Resource
    private AudioTextMapper audioTextMapper;
    @Resource
    private FileService fileService;
    @Resource
    private TTSServiceFactory ittsService;
    @Resource
    private LmAudioService lmAudioService;
    @Resource
    private LmrobotResourceConfig lmrobotResourceConfig;

    private EventExecutor executor = new DefaultEventExecutor();
    private EventExecutorGroup eventExecutors;

    @PostConstruct
    public void init() {
        if (!lmrobotResourceConfig.isOpenAudioConvertTask()) {
            log.warn("未开启文本转语音的任务");
            return;
        }
        eventExecutors = new DefaultEventExecutorGroup(lmrobotResourceConfig.getConvertAudioLevel());
        this.executor = eventExecutors.next();
        log.warn("开启文本转换语音的任务");
        executor.scheduleWithFixedDelay(() -> {
            convertAudio();
        }, 60, 60, TimeUnit.SECONDS);
    }

    public void convertAudio() {
        executor.execute(() -> {
            try {
                this.eventExecutors.execute(this::createAudio);
            } catch (Throwable e) {
                log.warn("文本生成角色音频异常", e);
            }
        });
    }

    private void createAudio() {
        List<RoleTextAudioDO> roleTextForCreateAudio = roleTextAudioMapper.getRoleTextForCreateAudio();
        if (!roleTextForCreateAudio.isEmpty()) {
            log.info("开始把文本生成角色音频,数量: {}", roleTextForCreateAudio.size());
            int index = 0;
            for (RoleTextAudioDO roleTextAudioDO : roleTextForCreateAudio) {
                log.info("开始生成第{}条音频,roleId: {},textId: {}", ++index, roleTextAudioDO.getAudioToneId(), roleTextAudioDO.getAudioTextId());
                try {
                    callAiToCreateAudio(roleTextAudioDO);
                } catch (Throwable e) {
                    log.error("文本转换音频异常", e);
                }
            }
        }
    }

    /**
     * 调用ai接口生成音频，并上传音频，返回音频的文件id
     *
     * @param roleTextAudioDO
     * @return
     */
    private void callAiToCreateAudio(RoleTextAudioDO roleTextAudioDO) {
        AudioToneDO audioTone = audioToneService.getAudioTone(roleTextAudioDO.getAudioToneId());
        if (audioTone == null) {
            log.warn("声纹不存了，删除生成记录,id: {}", roleTextAudioDO.getId());
            // 没有此声纹了，把生成记录删除掉
            audioToneService.deleteAudioTone(roleTextAudioDO.getAudioToneId());
            // 生成记录也删除，不生成了
            roleTextAudioMapper.deleteById(roleTextAudioDO.getId());
            return;
        }
        UploadFileResult uploadFileResult = fileService.getFile(audioTone.getFileId().longValue(), (int) Duration.ofMinutes(30).toSeconds());
        AudioTextDO audioTextDO = audioTextMapper.selectById(roleTextAudioDO.getAudioTextId());
        if (audioTextDO == null) {
            log.warn("文本不存在，删除生成记录,id: {}", roleTextAudioDO.getId());
            audioTextMapper.deleteById(roleTextAudioDO.getAudioTextId());
            roleTextAudioMapper.deleteById(roleTextAudioDO.getId());
            return;
        }
        String ext = FileNameUtil.extName(uploadFileResult.getFileName());
        String voiceHash = String.valueOf(uploadFileResult.getFileId());
        final String cloneVoiceId = audioTone.getCloneVoiceIdByTssName(ittsService.getPrimaryName());
        log.info("查询cloneVoiceId, cloneVoiceId = {}, ttsName = {}, tone = {}", cloneVoiceId, ittsService.getPrimaryName(), audioTone);
        byte[] audioBytes = ittsService.getService().convertTextToSpeech(audioTone.getId(), cloneVoiceId, audioTone.getName(), uploadFileResult.getFileUrl(), voiceHash, ext, "mp3", audioTextDO.getContent());
        if (audioBytes == null || audioBytes.length == 0) {
            log.warn("文本转换的角色音频为空id: {},roleId: {}, textId: {}", roleTextAudioDO.getId(), roleTextAudioDO.getAudioToneId(), roleTextAudioDO.getAudioTextId());
        } else {
            log.info("生成音频成功，开始本地存储");
            String name = audioTone.getName() + audioTextDO.getId() + ".mp3";
            String path = "role/audio/" + name;
            uploadFileResult = fileService.createFile(name, path, audioBytes, null);
            if (uploadFileResult != null) {
                Long fileId = uploadFileResult.getFileId();
                // 插入标签和关键字
                LmAudioSaveReqVO lmAudioSaveReqVO = new LmAudioSaveReqVO();
                lmAudioSaveReqVO.setName(name);
                lmAudioSaveReqVO.setFileId(fileId);
                lmAudioSaveReqVO.setAudioToneId(audioTone.getId());
                lmAudioSaveReqVO.setTextDesc(audioTextDO.getContent());
                if (audioTextDO.getTagList() != null) {
                    List<Integer> tagList = JSON.parseArray(audioTextDO.getTagList(), Integer.class);
                    lmAudioSaveReqVO.setTagIdArray(tagList);
                }
                if (audioTextDO.getKeyworldList() != null) {
                    List<Integer> keyWordList = JSON.parseArray(audioTextDO.getKeyworldList(), Integer.class);
                    lmAudioSaveReqVO.setKeyWordIdArray(keyWordList);
                }
                List<AudioRelationSaveVo> relationAudio = this.createRelationAudio(ext, audioTone, audioTextDO, roleTextAudioDO, uploadFileResult.getFileUrl());
                lmAudioSaveReqVO.setAudioRelationList(relationAudio);
                lmAudioSaveReqVO.setRelationType(audioTextDO.getRelationType());
                Integer audioId = lmAudioService.createAudio(lmAudioSaveReqVO);
                roleTextAudioDO.setAudioId(audioId);
                // 标记完成状态
                roleTextAudioDO.setStatus(1);
                roleTextAudioMapper.updateById(roleTextAudioDO);
                log.info("创建音频成功");

            } else {
                log.warn("上传音频文件失败");

            }
        }
    }

    private List<AudioRelationSaveVo> createRelationAudio(String ext, AudioToneDO cosplayDO, AudioTextDO audioTextDO, RoleTextAudioDO roleTextAudioDO, String audioToneUrl) {
        if (audioTextDO.getRelationContent() != null) {
            List<AudioTextRelation> audioTextRelationList = JSON.parseArray(audioTextDO.getRelationContent(), AudioTextRelation.class);
            if (audioTextRelationList == null || audioTextRelationList.isEmpty()) {
                return new ArrayList<>(1);
            }
            List<Integer> audioIds = new ArrayList<>();
            int index = 0;
            List<AudioRelationSaveVo> audioRelationSaveVos = new ArrayList<>(audioTextRelationList.size());
            for (AudioTextRelation audioTextRelation : audioTextRelationList) {
                if (StringUtils.isNotEmpty(audioTextRelation.getRelationText())) {
                    String voice_hash = String.valueOf(cosplayDO.getFileId());
                    final String cloneVoiceId = cosplayDO.getCloneVoiceIdByTssName(ittsService.getPrimaryName());
                    log.info("查询cloneVoiceId, cloneVoiceId = {}, ttsName = {}, tone = {}", cloneVoiceId, ittsService.getPrimaryName(), cosplayDO);
                    byte[] audioBytes = ittsService.getService().convertTextToSpeech(cosplayDO.getId(), cloneVoiceId, cosplayDO.getName(), audioToneUrl, voice_hash, ext, "mp3", audioTextRelation.getRelationText());
                    if (audioBytes == null || audioBytes.length == 0) {
                        log.warn("文本转换的角色音频为空,roleId: {}, textId: {}", roleTextAudioDO.getId(), roleTextAudioDO.getAudioTextId());
                    } else {
                        String name = cosplayDO.getName() + audioTextDO.getId() + "#" + (++index) + ".mp3";
                        String path = "role/audio/" + name;
                        UploadFileResult uploadFileResult = fileService.createFile(name, path, audioBytes, null);
                        if (uploadFileResult != null) {
                            Long fileId = uploadFileResult.getFileId();
                            LmAudioDO audioDO = new LmAudioDO();
                            audioDO.setName(name);
                            audioDO.setFileId(fileId);
                            audioDO.setAudioToneId(cosplayDO.getId());
                            audioDO.setTextDesc(audioTextDO.getContent());
                            audioDO.setCreator("AI Relation");
                            lmAudioMapper.insert(audioDO);
                            audioIds.add(audioDO.getId());
                            AudioRelationSaveVo audioRelationSaveVo = new AudioRelationSaveVo();
                            audioRelationSaveVo.setDefaultCon(audioTextRelation.isDefaultCon());
                            audioRelationSaveVo.setAudioId(audioDO.getId());
                            audioRelationSaveVo.setIds(audioTextRelation.getKeywordIds());
                            audioRelationSaveVos.add(audioRelationSaveVo);
                        } else {
                            log.warn("上传音频文件失败");
                        }

                    }
                }
            }
            if (!audioIds.isEmpty()) {
                roleTextAudioDO.setRelationAudio(JSON.toJSONString(audioIds));
            }
            return audioRelationSaveVos;
        }
        return null;
    }

}
